﻿using HPMetrics.Diagnostics;
using Network.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Data.Json;

namespace HPMetrics
{
    public class App
    {
        public string Id;
        public string Name;
        public string Version;
    }

    public class Device
    {
        public string Ssid;
        public string Sn;
    }
    public class Event
    {
        public int Id;
        public string Content;
        public Int64 StartAt;
        public Int64 Duration;
    }

    public class Token
    {
        public string Value;
        public string Type;
    }
    public class Metrics
    {
        public static bool IsEnabled { get; set; } = true;
        public string Host { get; set; }
        public Token Token { get; set; }
        public App App { get; set; }
        public Device Device { get; set; }

        public static void Initialize(string host, Token token, App app, Device device)
        {
            Instance.Host = host;
            Instance.Token = token;
            Instance.App = app;
            Instance.Device = device;
        }

        public static async Task<Int64?> Timestamp()
        {
            return await Instance.GetTimestamp().ConfigureAwait(false);
        }

        public static async Task<bool> Track(string user, int evtId, string content = "", Int64 startAt = 0, Int64 duration = 0)
        {
            if (!IsEnabled)
            {
                Debug.WriteLine("Track:Disabled");
                return false;
            }

            Debug.WriteLine($"Track, user:{user}, event:[{evtId}, {content}, {startAt}, {duration}]");
            return await Instance.TrackEvent(user, new Event 
            {
                Id = evtId,
                Content = content,
                StartAt = startAt,
                Duration = duration
            });
        }

        private async Task<Int64?> GetTimestamp()
        {
            if (Token == null || string.IsNullOrEmpty(Host))
            {
                Debug.WriteLine("Before calling GetTimestamp, please set the 'Token' and 'Host' Property.");
                return null;
            }
            string restfulApi = "/xiaowei/client/v1/timestamp";
            var response = await HttpRequest.GetAsync(Host + restfulApi, Token.Type, Token.Value);
            try
            {
                JsonObject jsonObject = JsonObject.Parse(response);
                return (Int64)jsonObject.GetNamedNumber("timestamp");
            }
            catch
            {
                return null;
            }
        }
        
        private async Task<bool> TrackEvent(string user, Event evt)
        {
            Debug.WriteLine("TraceEvent:start");
            string restfulApi = "/xiaowei/client/v1/event";

            if (Token == null || App == null || Device == null || string.IsNullOrEmpty(Host))
            {
                Debug.WriteLine("Before calling TrackEvent, please set the 'Host', 'Token', 'App', 'Device' Properties.");
                Debug.WriteLine("TraceEvent:end with wrong parameters");
                return false;
            }

            JsonObject appObject = new JsonObject();
            appObject.SetNamedValue("id", JsonValue.CreateStringValue(App.Id));
            appObject.SetNamedValue("name", JsonValue.CreateStringValue(App.Name));
            appObject.SetNamedValue("version", JsonValue.CreateStringValue(App.Version));

            JsonObject deviceObject = new JsonObject();
            deviceObject.SetNamedValue("ssid", JsonValue.CreateStringValue(Device.Ssid));
            deviceObject.SetNamedValue("sn", JsonValue.CreateStringValue(Device.Sn));

            JsonObject evtObject = new JsonObject();
            evtObject.SetNamedValue("id", JsonValue.CreateNumberValue(evt.Id));
            evtObject.SetNamedValue("content", JsonValue.CreateStringValue(evt.Content));
            evtObject.SetNamedValue("startAt", JsonValue.CreateNumberValue(evt.StartAt));
            evtObject.SetNamedValue("duration", JsonValue.CreateNumberValue(evt.Duration));

            JsonObject root = new JsonObject();
            root.SetNamedValue("app", appObject);
            root.SetNamedValue("device", deviceObject);
            root.SetNamedValue("event", evtObject);
            root.SetNamedValue("user", JsonValue.CreateStringValue(user));

            
            try
            {
                var response = await HttpRequest.PostAsync(Host + restfulApi, Token.Type, Token.Value, root.ToString());
                Debug.WriteLine($"TrackEvent, {response}");

                JsonObject jsonObject = JsonObject.Parse(response);
                bool ret =  (int)jsonObject.GetNamedNumber("code") == 201 ? true : false;
                Debug.WriteLine("TraceEvent:end with OK");
                return ret;
            }
            catch (Exception)
            {
                Debug.WriteLine("TraceEvent:end with Crashed");
                return false;
            }
        }

        private static Metrics Instance { get { return LazyInstance.Value; } }

        private static readonly Lazy<Metrics> LazyInstance = new Lazy<Metrics>(() =>
        {
            return new Metrics();
        }, LazyThreadSafetyMode.ExecutionAndPublication);
    }
}
